/**
 * 
 */
package edu.umd.clip.lm.factors;

import org.w3c.dom.*;

import java.util.*;

import edu.umd.clip.lm.util.*;

/**
 * @author Denis Filimonov <den@cs.umd.edu>
 *
 */
public class WordClass implements WordToOvertFactorInterface {
	private final static String XML_WORD_NAME = "w";
	private final static String XML_CLASS_ATTR_NAME = "c";
	private final static String XML_WORD2CLASS_NAME = "word-to-class";
	
	private final Map<String,String> word2class;
	private String[] POSSIBLE_UNK_VALUES;
	
	public WordClass(Map<String,String> word2class) {
		this.word2class = word2class;
	}
	
	public WordClass(Element xmlnode) {
		Element elem = XMLUtils.getFirstElementByTagName(xmlnode, XML_WORD2CLASS_NAME);
		
		NodeList nodes = XMLUtils.getChildrenElementsByTagName(elem, XML_WORD_NAME);
		int numWords = nodes.getLength();
		
		word2class = new HashMap<String,String>(numWords);
		
		for(int i=0; i<numWords; ++i) {
			Element e = (Element) nodes.item(i);
			String word = e.getTextContent();
			String cl = e.getAttribute(XML_CLASS_ATTR_NAME);
			word2class.put(word, cl);
		}
	}

	public void store(Element xmlnode) {
		Document doc = xmlnode.getOwnerDocument();
		Element elem = doc.createElement(XML_WORD2CLASS_NAME);
		xmlnode.appendChild(elem);
		
		for(Map.Entry<String, String> entry : word2class.entrySet()) {
			Element e = doc.createElement(XML_WORD_NAME);
			e.setTextContent(entry.getKey());
			e.setAttribute(XML_CLASS_ATTR_NAME, entry.getValue());
			elem.appendChild(e);
		}
	}
	
	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.factors.WordToOvertFactorInterface#wordToOvertFactor(java.lang.String)
	 */
	@Override
	public String wordToOvertFactor(String word) {
		String cl = word2class.get(word);
		if (cl == null) {
			return Dictionary.getUnkWord();
		}
		return cl;
	}

	/* (non-Javadoc)
	 * @see edu.umd.clip.lm.factors.WordToOvertFactorInterface#possibleUnkValues()
	 */
	@Override
	public String[] possibleUnkValues(Dictionary mainVocab) {
		if (POSSIBLE_UNK_VALUES == null) {
			synchronized(this) {
				if (POSSIBLE_UNK_VALUES == null) {
					HashSet<String> classes = new HashSet<String>(20000);
					classes.add(Dictionary.getUnkWord());
					
					for(Map.Entry<String,String> entry : word2class.entrySet()) {
						String word = entry.getKey();
						String cl = entry.getValue();
						if (Dictionary.isUnk(mainVocab.getId(word))) {
							classes.add(cl);
						}
					}
					POSSIBLE_UNK_VALUES = classes.toArray(new String[classes.size()]);		
				}
			}
		}
		return POSSIBLE_UNK_VALUES;
	}

}
